﻿using System.Collections.Generic;
using GCTrackableRace.Interfaces;
using GcTrackableRace.RemoteServices;
using log4net.Core;
using log4net;

namespace GcTrackableRace.ScoreCalculator.Helpers
{
	public class LocationInfoLookup : ILocationInfoLookup
	{
		private readonly Dictionary<string, ILocationInfo> _CoordInfo = new Dictionary<string, ILocationInfo>();

		public LocationInfoLookup(IGcTrackableRacePersistence persistence,IRemoteService remoteService, ILog log)
		{
			Persistence = persistence;

			RemoteService = remoteService;

			LoadLocationInfo();

			Log = log;
		}

		private IGcTrackableRacePersistence Persistence { get; set; }

		private IRemoteService RemoteService { get; set; }

		private ILog Log { get; set; }

		public string GetCountryCodeUsingCoords(double? latitude, double? longitude)
		{
			Log.Info(string.Format("  GetCountryCodeUsingCoords : {0}, {1}", latitude, longitude));

			if (latitude == null || longitude == null)
				return "Unknown";

			var lookupKey = CreateKey(latitude ,longitude);

			Log.Debug(string.Format("    lookupKey : {0}", lookupKey));

			if (_CoordInfo.ContainsKey(lookupKey))
			{
				Log.Debug(string.Format("    Found lookupKey"));

				return _CoordInfo[lookupKey].CountryCode;			
			}

			Log.Debug(string.Format("    GetFromInternet()"));

			var locationInfo = GetFromInternet(latitude, longitude);

			if (locationInfo != null)
			{
				Log.Debug(string.Format("    result in not null"));

				Log.Debug(string.Format("    _CoordInfo.Add"));

				_CoordInfo.Add(lookupKey, locationInfo);

				Log.Debug(string.Format("    PersistLocationInfo()"));
				
				Persistence.PersistLocationInfo(locationInfo);

				Log.Debug(string.Format("    return locationInfo"));

				return locationInfo.CountryCode;
			}

			Log.Debug(string.Format("    return 'Unknown'"));
			
			return "Unknown";
		}

		public string GetProvinceOrStateUsingCoords(double? latitude, double? longitude)
		{
			if (latitude == null || longitude == null)
				return "Unknown-Unknown";

			var lookupKey = CreateKey(latitude, longitude);

			if (!_CoordInfo.ContainsKey(lookupKey))
			{
				var locationInfo = GetFromInternet(latitude, longitude);

				if (locationInfo == null)
				{
					return "Unknown-Unknown";
				}

				_CoordInfo.Add(lookupKey, locationInfo);

				Persistence.PersistLocationInfo(locationInfo);
			}

			var info = _CoordInfo[lookupKey];

			return string.Format("{0}-{1}", info.CountryCode, info.StateCode);
		}


		#region Private Methods

		private ILocationInfo GetFromInternet(double? latitude, double? longitude)
		{
			var remoteService = new RemoteService() as IRemoteService;

			var locationInfo = remoteService.GetLocationInfo(latitude, longitude);

			return locationInfo;
		}

		private string CreateKey(double? latitude, double? longitude)
		{
			return string.Format("{0},{1}", latitude, longitude);
		}

		private void LoadLocationInfo()
		{
			var coordInfoList = Persistence.GetAllLocationInfos();

			foreach (var coordInfo in coordInfoList)
			{
				var lookupKey = CreateKey(coordInfo.Latitude, coordInfo.Longitude);

				_CoordInfo.Add(lookupKey, coordInfo);
			}
		}

		#endregion Private Methods
	}
}
